/*****************************************************************************
 *   Copyright 2005 Tim A Wang
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 ****************************************************************************/
package com.jb.framework.database;

import com.jb.util.Meter;

import java.math.BigDecimal;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * Command that updates database
 *
 * @author $author$
 * @version $Revision$
 */
public class UpdateDBCommand {
    Predicate predicate;
    String sql = null;
    private HashMap bindVariable = new HashMap();

    /**
     * Creates a new UpdateDBCommand object.
     *
     * @param s Parameter
     */
    public UpdateDBCommand(String s) {
        sql = s;
    }

    /**
     * Execute an sql statement on a passed in connection.
     * @param stmt parameter
     * @param c DOCUMENT ME!
     *
     * @return return-value
     *
     * @throws SQLException exception
     */
    public static boolean executeStmt(String stmt, Connection c)
        throws SQLException {
        UpdateDBCommand s = new UpdateDBCommand(stmt);
        s.execute(c);

        return true;
    }

    public static boolean executeStmt(String stmt, Predicate predicate, Connection c)
        throws SQLException {
        PreparedStatement statement = null;

        try {
            statement = c.prepareStatement(stmt);

            if (predicate != null) {
                predicate.bindStatement(statement);
            }

            statement.execute();
        } finally {
            if (statement != null) {
                statement.close();
            }
        }

        return true;
    }

    public static boolean executeStmt(String stmt) throws SQLException {
        Object obj = new Object();
        Connection c = com.jb.framework.DataSourceManager.getConnection(obj);
        UpdateDBCommand s = new UpdateDBCommand(stmt);

        try {
            s.execute(c);

            return true;
        } finally {
            com.jb.framework.DataSourceManager.releaseConnection(obj, c);
        }
    }

    /**
     * Adds  a binding variable.
     *
     * @param varName name of the variable.
     * @param bindVar value of the variable.
     */
    public void addBindVariable(String varName, Object bindVar) {
        bindVariable.put(varName, bindVar);
    }
  /**
   * Execute this SQL command.
   * @param bindingVariables to be bound by order in the list.
   * @return number of records has been updated in database if suceed.
   * @throws java.sql.SQLException
   */
    public int execute(List bindingVariables, Connection c)
        throws SQLException {
        Meter.start(); 
        bindVariable.clear();

        int i = 1;

        for (Iterator iter = bindingVariables.iterator(); iter.hasNext();) {
            bindVariable.put("" + i, iter.next());
            i++;
        }

        PreparedStatement stmt = null;

        try {
            int ret;
            stmt = c.prepareStatement(sql);
            bindVariables(stmt);
            ret = stmt.executeUpdate();

            c.commit();

            return ret;
        } catch (SQLException e) {
            c.rollback();
            throw e;
        } finally {
            if (stmt != null) {
                stmt.close();
                stmt = null;
            }
            Meter.stop(sql); 
        }
    }

  /**
   * Executes this SQL command.
   * @param bindingVariables to be bound by hash key.
   * @param connection over which this command is performed.
   * @return number of records has been updated in database if suceed.
   * @throws java.sql.SQLException
   */
    PreparedStatement stmt = null;
    
    public int execute(Map bindingVariable, Connection c)
        throws SQLException {
        Meter.start(); 
        try {
            int ret;
            bindVariable.putAll(bindingVariable);
            if(stmt==null)
              stmt = c.prepareStatement(sql);
              
            bindVariables(stmt);
            ret = stmt.executeUpdate();
            return ret;
        } catch (SQLException e) {
            c.rollback();
            throw e;
        } finally {
            if (stmt != null) {
                stmt.close();
                stmt = null;
            }
            Meter.stop("UpdateDBCommand.execute"); 
        }
    }

  /**
   * Executes this SQL command.
   * @return number of records has been updated in database if suceed.
   * @throws java.sql.SQLException
   */
   public int execute(Connection c) throws SQLException {
        PreparedStatement stmt = null;

        try {
            int ret;
            stmt = c.prepareStatement(sql);
            bindVariables(stmt);
            ret = stmt.executeUpdate();
            c.commit();
            stmt.close();
            stmt = null;

            return ret;
        } catch (SQLException e) {
            c.rollback();
            throw e;
        } finally {
            if (stmt != null) {
                stmt.close();
                stmt = null;
            }
        }
    }

    private void bindVariables(PreparedStatement stmt)
        throws SQLException {
        int i = bindVariable.size();

        for (int j = 1; j < (i + 1); j++) {
            Object var = bindVariable.get("" + j);

            if (var instanceof String) {
                if (((String) var).length() == 0) {
                    stmt.setString(j, null);
                } else {
                    stmt.setString(j, (String) var);
                }
            } else if (var instanceof java.util.Date) {
                Date utlDate = (java.util.Date) var;
                Timestamp sqlDate = new Timestamp((utlDate.getTime()));
                stmt.setTimestamp(j, sqlDate);
            } else if (var instanceof Calendar) {
                Calendar utlDate = (Calendar) var;
                Timestamp sqlDate = new Timestamp((utlDate.getTime().getTime()));
                stmt.setTimestamp(j, sqlDate, utlDate);
            } else if (var instanceof BigDecimal) {
                stmt.setBigDecimal(j, (BigDecimal) var);
            } else if (var instanceof Boolean) {
                boolean bVar = ((Boolean) var).booleanValue();
                stmt.setBoolean(j, bVar);
            } else if (var == null) {
                stmt.setString(j, null);
            } else {
                stmt.setString(j, "" + var);
            }
        }
    }
}
